#ifndef CAMERA_INTERFACE_HEADER
#define CAMERA_INTERFACE_HEADER

#include "glm/glm.hpp"
#include "glm/ext.hpp"
#include "ICamera.h"

class DCamera : public ICamera<glm::vec3, glm::mat4x4, DCamera> {
public:
	DCamera(float w, float h)
		: 
		mEye( glm::vec3(0, 0, 1) ),
		mCenter( glm::vec3(0, 0, 0) ),
		mUp( glm::vec3(0, 1, 0) ),
		mFovy(75),
		mAspect(w/h),
		mNear(0.1f),
		mFar(1)
	{
		InitMVMatrix();
		InitPMatrix();
	}


	void Rotate( const glm::vec3 & axis, float angDeg ) {

		glm::mat4x4 rotMat = glm::rotate(angDeg, axis);
		mUp = glm::vec3(rotMat*glm::vec4(mUp, 0));

		InitMVMatrix();
	};

	//Implements the ISetPos
	void SetPos( const glm::vec3 & worldPos ) {
		mEye = worldPos;

		InitMVMatrix();
	}

	const glm::vec3 & GetPos ( ) {
		return mEye;
	}

	void SetUp( const glm::vec3 & up ) {
		mUp = up;

		InitMVMatrix();
	}

	void SetTarget( const glm::vec3 & worldPos ) {
		mCenter = worldPos;
		InitMVMatrix();
	}

	void SetFovy( float fovy ) {
		mFovy = fovy;
		InitPMatrix();
	}

	void SetAspect( float aspect ) {
		mAspect = aspect;
		InitPMatrix();
	}

	void SetNear(float near) {
		mNear = near;
		InitPMatrix();
	}

	void SetFar( float far) {
		mFar = far;
		InitPMatrix();
	}

	const glm::mat4x4 & GetMatrix (CAMERA_GET_ENUM flag) {
		//Set the matrices

		switch(flag){
		case MODELVIEW_MATRIX:
			{
				return this->mMVMat;
			}
			break;
		case PROJECTION_MATRIX:
			{
				return this->mPMat;
			}
			break;
		default:
			assert(false);
			break;
		}

		return mMVMat;
	}

private:

	void InitMVMatrix() {
		mMVMat = glm::lookAt(mEye, mCenter, mUp);
	}

	void InitPMatrix() {
		mPMat = glm::perspective(mFovy, mAspect, mNear, mFar);
	}

	//For modelview parameters
	glm::vec3 mEye;
	glm::vec3 mCenter;
	glm::vec3 mUp;

	//For projection parameters
	float mFovy;
	float mAspect;
	float mNear;
	float mFar;

	//Perspective matrix
	glm::mat4x4 mPMat;

	//Modelview matrix
	glm::mat4x4 mMVMat;
};

#endif